package com.xhl.demo.async;

import cn.hutool.core.util.RandomUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.async.DeferredResult;

import java.util.concurrent.Callable;

/**
 * @author 徐宏亮
 * @description
 * 同步处理时，tomcat 的线程是有数量的
 * 异步处理时，可以让主线程调用副线程处理请求，服务器的吞吐量有一定的提升
 * @date 2019/1/16 13:50
 */
@RestController
public class AsyncController {
    private Logger logger = LoggerFactory.getLogger(getClass());

    @RequestMapping("/order1")
    public String order1() throws Exception {
        logger.info("主线程开始");
        Thread.sleep(1000);
        logger.info("主线程返回");
        return "success";
    }

    /**
     * 功能描述 使用Runnable异步处理Rest服务，满足的场景较少，副线程必须是主线程掉起
     * Callable 单开一个线程，使用 spring 管理线程做业务处理
     * @author 徐宏亮
     * @param
     * @return java.util.concurrent.Callable<java.lang.String>
     * @throws
     */
    @RequestMapping("/order2")
    public Callable<String> order2() {
        logger.info("主线程开始");
        Callable<String> result = () -> {
            logger.info("副线程开始");
            Thread.sleep(1000);
            logger.info("副线程返回");
            return "success";
        };
        logger.info("主线程返回");
        return result;
    }

    //消息队列
    @Autowired
    private MockQueue mockQueue;
    //消息处理结果
    @Autowired
    private DeferredResultHolder deferredResultHolder;

    /***
     * 功能描述
     * 有这种场景，应用1的线程1给消息队列发消息，线程2监听处理结果。
     * 应用2监听消息队列并处理消息，在发送处理结果给消息队列
     * @author 徐宏亮
     * @date 2019/3/2 13:09
     * @param
     * @return org.springframework.web.context.request.async.DeferredResult<java.lang.String>
     */
    @RequestMapping("/order3")
    public DeferredResult<String> order3() throws InterruptedException {
        logger.info("主线程开始");
        //生成随机数
        String orderNumber = RandomUtil.randomNumbers(8);
        //放入消息队列
        mockQueue.setPlaceOrder(orderNumber);

        //保存处理结果
        DeferredResult<String> result = new DeferredResult<>();
        deferredResultHolder.getMap().put(orderNumber, result);

        logger.info("主线程返回");
        return result;
    }

}
